#!/usr/bin/python
from xml.sax import make_parser
from xml.sax.handler import ContentHandler
#Other
import sys,os

lastElement = -1
terrain = ["mountain","grass","desert","water"]

debuglevel = 100
def debug(message,level=10):
	if debuglevel >= level:
		sys.stderr.write(message + "\n")

###########################
# Parsing classes
###########################
#XML Format:
#<map columns="10" rows="5" players="2" name="lolz">
           #<row> 
                 #<forest/> <forest/> <mountain/> <grass><unit player="1">siege</unit>
           #</row>
        
      #... More rows

#</map>

class MapHandler( ContentHandler ):
	def __init__(self):
		self._MapArray = []
		self.maxplayers = 0
		# Parsing sanity variables
		self.row = 0
		self.column = 0
		self.buffer = ""
		self.element = None
		self.terrain = None
		self.unit = None
		self.player = None
		self.name = None

	def startElement( self, name, attrs ):
		self.element = name
		self.buffer = ""

##		if name == "columns":
##			pass #columns added as terrain is added

		debug(name)
		if name == "map":
			pass # should assign name
		
		elif name == "row":
			self._MapArray.append([]) # add another row

##		elif filter(lambda x: x == name, ["columns","rows","name","players"]):
##			debug("#2 activated")
			
		elif name is not "unit":
			self.terrain = name
			# Add another column
			
			if attrs.has_key('unit'):
				self._MapArray[lastElement].append((name,attrs.getValue("unit")))
			else:
				self._MapArray[lastElement].append((name,None))
		elif name is "unit":
			self.player = attributes["player"]

		else:
			debug("skipped "+name)

	def characters(self, data):
		self.buffer += data
		# read to self.buffer

	def endElement( self, name ):
		# Misc
		if name is "unit":
			self.unit = self.buffer
		if name is "players":
			self.maxplayers = int(self.buffer)

		# add buffer to self._MapArray
		if filter(lambda x: x == name, terrain):
			self._MapArray[self.column][self.row] = (self.terrain, self.unit, self.player)
			self.column += 1

		if name == "row":
			self.row += 1
			self.column = 0

		# cleanup
		self.buffer = ""
		self.element = None
		self.terrain = None
		self.unit = None

	def getPlayers(self):
		return self.maxplayers

	def setPlayers(self,number):
		self.maxplayers = number

	def getColumnNum(self):
		return len(self._MapArray[0])

	def getRowNum(self):
		return len(self._MapArray)

	def setUnit(self,column,row,unit):
		try:
			self._MapArray[row][column] = (self._MapArray[row][column][0],unit)
		except:
			raise SetUnitError

	def setTerrain(self,col1,row1,terrain):
		try:
			#~ print "Before: "
			self._MapArray[row1][col1] = (terrain,self._MapArray[row1][col1][1])
			#~ print "After: "
		except:
			debug("exception",self._MapArray[row1][col1] + "<- self._MapArray[column][row]")


class MapParse:
	def __init__(self,mapfile):
		self.parse  = make_parser()
		self.handler = MapHandler()
		self.parse.setContentHandler(self.handler)
		try:
			self.parse.parse(mapfile)
		except ValueError:
			debug("File not found! Make sure " + mapfile + " is a valid file, and that the path is correct.")
			raise WrongFileName
	def getColumnNum(self):
		return self.handler.getColumnNum()
	def getRowNum(self):
		try:
			return self.handler.getRowNum()
		except:
			return None
	def getRow(self,index):
		try:
			return self.handler._MapArray[index]
		except:
			pass
	def getUnit(self,column,row):
		try:
			return self.handler._MapArray[column][row][1]
		except:
			return None
	def getTerrain(self,column,row):
		try:
			return self.handler._MapArray[column][row][0]
		except:
			debug(str(sys.exc_info()[0])+str(sys.exc_info()[1])+str(column)+" "+str(row))
			return None
	def setUnit(self,column,row,unit):
		try:
			self.handler.setUnit(column,row,unit)
			#~ print "call success"
		except:
			pass
	def setTerrain(self,column,row,terrain):
		try:
			self.handler.setTerrain(column,row,terrain)
		except:
			print "exception"
			print "This is the affected bit of table: "+ str(self.handler._MapArray[column][row])

###########################
# XML output
###########################
#XML Format:
#<map>
      #<columns>10</columns>
      #<rows>5</rows>
      #<players>2</players>
      #<name>Mike's Palace Of Terror</name> 

           #<row> 
                 #<forest/> <forest/> <mountain/> <grass><unit player="1">siege</unit>
           #</row>
        
      #... More rows

#</map>

def XML_Out(Map,targetfile,players=2,name=None):
	""" The structure of Map should be:
		Map[Column][Row][0] -> Terrain
		Map[Column][Row][1] -> Unit
		Map[Column][Row][2] -> Player who owns the unit
		
	   `targetfile` should be an open file descriptor
	   
	   This method outputs in a ROW BASED file format, though it receives a COLUMN BASED array.
	   This may cause bugs.
	"""
	if type([]) == type(Map):
		# Header
		output = """<?xml version="1.0"?>\n"""
		# Columns
		output += """<columns>%d</columns>\n""" % len(Map)
		#Rows
		output += """<rows>%d</rows>\n""" % len(Map[0])
		#Players
		output += """<players>%d</players>\n""" % players
		#Name [optional]
		if name is not None:
			output += """<name>%s</name>\n""" % name

        # Everything assumes rectangular:        
		for i in range(len(Map[0])):
			output += """<row>"""

            # We need to reverse the in-memory representation for output
			for j in range(len(Map)):
				if Map[j][i][1] is None: # If there is no unit
					output += """<%s/>""" % Map[j][i][0]
				else: # ain't dat ugly?
					output += """<%s><unit player="%d">%s</unit></%s>""" % (Map[j][i][0], Map[j][i][2], Map[j][i][1], Map[j][i][0])
					
			output += """</row>"""
		output += """</map>"""
		targetfile.write(output)
		targetfile.close()
	else:
        #FIXME: hardcoded player #
		# Header
		output = """<?xml version="1.0"?>\n"""
		# Columns
		output += """<columns>%d</columns>\n""" % Map.getColumnNum()
		#Rows
		output += """<rows>%d</rows>\n""" % Map.getRowNum()
		#Players
		output += """<players>%d</players>\n""" % players
		#Name [optional]
		if name is not None:
			output += """<name>%s</name>\n""" % name

		for i in range(Map.getRowNum()):
			
			output += """<row>"""
			
			for j in range(Map.getColumnNum(i)):
				if Map.getUnit(i,j) is None:
					output += """<%s/>""" % Map[j][i][0]
				else:
					output += """<%s><unit player="%d">%s</unit></%s>""" % (Map.getTerrain(i,j), Map.getPlayer(i,j), Map.getUnit(i,j), Map.getTerrain(i,j))		
			
			output += """</row>"""
			
		output += """</map>"""
		targetfile.write(output)
		targetfile.close()
